using UnityEngine;
using System.Collections;

public abstract class Player : WorldObject, PlayerInterface
{

	private CommandSource commandSource;
	
	protected AffectableSpeed movementSpeed;
	protected AffectableSpeed rotationSpeed;
	protected string walkAnimationName;
	private Item item = Item.None;
	
	public virtual void Start()
	{
		gameObject.GetComponentInChildren<AnimatedModel>().setAnimationName(walkAnimationName);
	}
	// Update is called once per frame
	public virtual void Update ()
	{
		
		bool animationEnabled = false;
		if(commandSource.consumeMoveForward())
		{
			animationEnabled = true;
			move(1.0f);
		}
		if(commandSource.consumeMoveBackward())
		{
			animationEnabled = true;
			move(-1.0f);
		}
		if(commandSource.consumeRotateLeft())
		{
			animationEnabled = true;
			rotate(-1.0f);
		}
		if(commandSource.consumeRotateRight())
		{
			animationEnabled = true;
			rotate(1.0f);
		}
		if(commandSource.consumeSecondarySkill()){
			useItem();
		}
		if(animationEnabled)
			gameObject.GetComponentInChildren<AnimatedModel>().setAnimationEnabled(true);	
		else
			gameObject.GetComponentInChildren<AnimatedModel>().setAnimationEnabled(false);
		
		commandSource.reset();
		
		fixPositionAndHeading();
	}
	private void fixPositionAndHeading()
	{
		Vector3 spherePosition = GameObject.Find("Sphere").transform.position; //Vector3.zero
		Vector3 newDiff = (gameObject.transform.position - spherePosition);
		if(newDiff.magnitude != Balance.SPHERE_RADIUS)
		{
			//gameObject.rigidbody.velocity = Vector3.zero;
			gameObject.rigidbody.SetMaxAngularVelocity(0);
			//gameObject.rigidbody.;
			
			newDiff = newDiff.normalized * Balance.SPHERE_RADIUS;
			gameObject.transform.position = newDiff;
			Vector3 a = Vector3.Cross(newDiff, getHeading());
			
			gameObject.transform.LookAt(newDiff + Vector3.Cross(newDiff, a), (this is Destroyer ? -1 : 1 ) * newDiff);
		}
	}
	public abstract void reset();
	
	private Vector3 getHeading()
	{
		Vector3 a = gameObject.transform.position;
		gameObject.transform.Translate(new Vector3(0, 0, 0.1f));
		Vector3 b = gameObject.transform.position;
		gameObject.transform.Translate(new Vector3(0, 0, -0.1f));
		
		return (a - b).normalized;
	}
	private void move(float intensity)
	{
		
		float angle = intensity * movementSpeed.get() * 200.0f; // TODO dependent on radius and distance, make configurable, * factor
		
		Vector3 spherePosition = GameObject.Find("Sphere").transform.position; //Vector3.zero
		
		Vector3 a = gameObject.transform.position;
		gameObject.transform.Translate(new Vector3(0, 0, 0.1f));
		Vector3 b = gameObject.transform.position;
		gameObject.transform.Translate(new Vector3(0, 0, -0.1f));
			
		Vector3 positionDiff = a - spherePosition;
		
		Vector3 playerHeading = getHeading();
		Vector3 axis = Vector3.Cross(playerHeading, positionDiff);
		gameObject.transform.RotateAround(spherePosition, axis, angle * Time.deltaTime);
		
	}
	
	private void rotate(float intensity)
	{
		float angle = intensity * rotationSpeed.get() * 200.0f; //TODO * factor
		gameObject.transform.Rotate(new Vector3(0, angle * Time.deltaTime, 0));
	}
	
	public CommandSource getCommandSource()
	{
	    return commandSource;
	}
	public AffectableSpeed getMovementSpeed()
	{
		return movementSpeed;
	}
	public AffectableSpeed getRotationSpeed()
	{
		return rotationSpeed;
	}
	public void setCommandSource(CommandSource cs)
	{
		commandSource = cs;
	}
	public void setItem(Item item){
		if(item == Item.None)
			Debug.Log("Warning: setItem(None) was called");
		if(!hasItem())
			this.item = item;
		else
			Debug.Log("Item not taken, item present: " + item.ToString());
	}
	public void useItem(){
		if(hasItem())
		{
			Debug.Log("used item");
			switch(item){
				case Item.SpeedUp:speedUp();break;
				case Item.SlowDown:slowDown();break;
				case Item.Multify:multify();break;
				case Item.None:;break;
			}
			item = Item.None;
		}
	}
	public bool hasItem(){
		return item != Item.None;
	}
	public Item getItem()
	{
		return item;
	}
	public abstract void speedUp();
	public abstract void slowDown();
	public abstract void multify();
	
}
